/*-------------------------------------------------------------------------
 *
 * libpq-fe.h
 *	  此文件包含前端 PostgreSQL 应用程序使用的结构和函数的 externs 的定义。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/interfaces/libpq/libpq-fe.h
 *
 *-------------------------------------------------------------------------
 */

#ifndef LIBPQ_FE_H
#define LIBPQ_FE_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>

/*
 * postgres_ext.h 定义了后端可外部访问的类型，
 * 如 Oid。
 */
#include "postgres_ext.h"

/*
 * 这些符号可以在编译时 #ifdef 测试中用于检查
 * 新版本的 libpq 特性是否可用。
 */
/* 表示 PQenterPipelineMode 和相关功能的存在 */
#define LIBPQ_HAS_PIPELINING 1
/* 表示 PQsetTraceFlags 的存在；还有新的 PQtrace 输出格式 */
#define LIBPQ_HAS_TRACE_FLAGS 1
/* 表示 PQsslAttribute(NULL, "library") 是有用的 */
#define LIBPQ_HAS_SSL_LIBRARY_DETECTION 1

/*
 * PQcopyResult 的选项标志
 */
#define PG_COPYRES_ATTRS		  0x01
#define PG_COPYRES_TUPLES		  0x02	/* 暗示 PG_COPYRES_ATTRS */
#define PG_COPYRES_EVENTS		  0x04
#define PG_COPYRES_NOTICEHOOKS	  0x08

/* 应用程序可见的枚举类型 */

/*
 * 虽然可以向这些列表中添加内容，但变得未使用的值
 * 永远不应删除，也不应重新定义常量 - 这将
 * 破坏与现有代码的兼容性。
 */

typedef enum
{
	CONNECTION_OK,
	CONNECTION_BAD,
	/* 下面的仅限非阻塞模式 */

	/*
	 * 不应依赖这些的存在 - 仅应将其
	 * 用于用户反馈或类似目的。
	 */
	CONNECTION_STARTED,			/* 正在等待连接建立。 */
	CONNECTION_MADE,			/* 连接正常；等待发送。 */
	CONNECTION_AWAITING_RESPONSE,	/* 等待来自
									 * postmaster 的响应。 */
	CONNECTION_AUTH_OK,			/* 已收到认证；等待
								 * 后端启动。 */
	CONNECTION_SETENV,			/* 此状态不再使用。 */
	CONNECTION_SSL_STARTUP,		/* 正在协商 SSL。 */
	CONNECTION_NEEDED,			/* 内部状态：需要 connect() */
	CONNECTION_CHECK_WRITABLE,	/* 正在检查会话是否为读写。 */
	CONNECTION_CONSUME,			/* 正在消耗任何额外消息。 */
	CONNECTION_GSS_STARTUP,		/* 正在协商 GSSAPI。 */
	CONNECTION_CHECK_TARGET,	/* 正在检查目标服务器属性。 */
	CONNECTION_CHECK_STANDBY	/* 正在检查服务器是否处于备用模式。 */
} ConnStatusType;

typedef enum
{
	PGRES_POLLING_FAILED = 0,
	PGRES_POLLING_READING,		/* 这两个指示可以	  */
	PGRES_POLLING_WRITING,		/* 在再次轮询之前使用 select。   */
	PGRES_POLLING_OK,
	PGRES_POLLING_ACTIVE		/* 未使用；保留一段时间以便向后
								 * 兼容 */
} PostgresPollingStatusType;

typedef enum
{
	PGRES_EMPTY_QUERY = 0,		/* 执行了空查询字符串 */
	PGRES_COMMAND_OK,			/* 一个不会返回
								 * 任何结果的查询命令已由
								 * 后端正确执行 */
	PGRES_TUPLES_OK,			/* 一个返回元组的查询命令已
								 * 由后端正确执行，PGresult
								 * 包含了结果元组 */
	PGRES_COPY_OUT,				/* 正在进行 Copy Out 数据传输 */
	PGRES_COPY_IN,				/* 正在进行 Copy In 数据传输 */
	PGRES_BAD_RESPONSE,			/* 从后端收到意外响应 */
	PGRES_NONFATAL_ERROR,		/* 通知或警告消息 */
	PGRES_FATAL_ERROR,			/* 查询失败 */
	PGRES_COPY_BOTH,			/* 正在进行 Copy In/Out 数据传输 */
	PGRES_SINGLE_TUPLE,			/* 从较大结果集中提取的单个元组 */
	PGRES_PIPELINE_SYNC,		/* 管道同步点 */
	PGRES_PIPELINE_ABORTED		/* 因管道中先前的中止而未能执行命令 */
} ExecStatusType;

typedef enum
{
	PQTRANS_IDLE,				/* 连接空闲 */
	PQTRANS_ACTIVE,				/* 正在进行命令 */
	PQTRANS_INTRANS,			/* 空闲，在事务块内 */
	PQTRANS_INERROR,			/* 空闲，在失败的事务中 */
	PQTRANS_UNKNOWN				/* 无法确定状态 */
} PGTransactionStatusType;

typedef enum
{
	PQERRORS_TERSE,				/* 单行错误消息 */
	PQERRORS_DEFAULT,			/* 推荐的样式 */
	PQERRORS_VERBOSE,			/* 所有事实，女士 */
	PQERRORS_SQLSTATE			/* 仅显示错误严重性和 SQLSTATE 代码 */
} PGVerbosity;

typedef enum
{
	PQSHOW_CONTEXT_NEVER,		/* 永远不显示 CONTEXT 字段 */
	PQSHOW_CONTEXT_ERRORS,		/* 仅对错误显示 CONTEXT（默认） */
	PQSHOW_CONTEXT_ALWAYS		/* 始终显示 CONTEXT 字段 */
} PGContextVisibility;

/*
 * PGPing - 不应更改此枚举的顺序，因为这些
 * 值通过 pg_isready 外部暴露。
 */

typedef enum
{
	PQPING_OK,					/* 服务器正在接受连接 */
	PQPING_REJECT,				/* 服务器处于活动状态但拒绝连接 */
	PQPING_NO_RESPONSE,			/* 无法建立连接 */
	PQPING_NO_ATTEMPT			/* 未尝试连接（参数错误） */
} PGPing;

/*
 * PGpipelineStatus - 当前管道模式状态
 */
typedef enum
{
	PQ_PIPELINE_OFF,
	PQ_PIPELINE_ON,
	PQ_PIPELINE_ABORTED
} PGpipelineStatus;

/* PGconn 封装到后端的连接。
 * 该结构的内容不应被应用程序所知。
 */
typedef struct pg_conn PGconn;

/* PGresult 封装查询的结果（更准确地说，是单个
 * SQL 命令 —— 提供给 PQsendQuery 的查询字符串可以包含多个
 * 命令，因此返回多个 PGresult 对象）。
 * 该结构的内容不应被应用程序所知。
 */
typedef struct pg_result PGresult;

/* PGcancel 封装需要取消在现有连接上
 * 运行的查询的信息。
 * 该结构的内容不应被应用程序所知。
 */
typedef struct pg_cancel PGcancel;

/* PGnotify 表示发生了 NOTIFY 消息。
 * 理想情况下，这将是一个不透明的 typedef，但它非常简单，
 * 因此不太可能发生变化。
 * 注意：在 Postgres 6.4 及以后的版本中，be_pid 是通知后端的，
 * 而在早期版本中，它始终是您自己后端的 PID。
 */
typedef struct pgNotify
{
	char	   *relname;		/* 通知条件名称 */
	int			be_pid;			/* 通知服务器进程的进程 ID */
	char	   *extra;			/* 通知参数 */
	/* 下面的字段对 libpq 是私有的；应用程序不应使用它们 */
	struct pgNotify *next;		/* 列表链接 */
} PGnotify;

/* 通知处理回调的函数类型 */
typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res);
typedef void (*PQnoticeProcessor) (void *arg, const char *message);

/* PQprint() 的打印选项 */
typedef char pqbool;

typedef struct _PQprintOpt
{
	pqbool		header;			/* 打印输出字段标题和行数 */
	pqbool		align;			/* 填充对齐字段 */
	pqbool		standard;		/* 旧的脑死格式 */
	pqbool		html3;			/* 输出 HTML 表格 */
	pqbool		expanded;		/* 展开表格 */
	pqbool		pager;			/* 如果需要，使用分页器输出 */
	char	   *fieldSep;		/* 字段分隔符 */
	char	   *tableOpt;		/* 插入到 HTML <table ...> */
	char	   *caption;		/* HTML <caption> */
	char	  **fieldName;		/* 替换字段名称的空终止数组 */
} PQprintOpt;

/* ----------------
 * PQconndefaults 或 PQconninfoParse 返回的 conninfo 参数定义的结构
 *
 * 除 "val" 之外的所有字段指向不应被更改的静态字符串。
 * "val" 要么是 NULL，要么是 malloc 创建的当前值字符串。PQconninfoFree()
 * 将释放 val 字符串和 PQconninfoOption 数组本身。
 * ----------------
 */
typedef struct _PQconninfoOption
{
	char	   *keyword;		/* 选项的关键字 */
	char	   *envvar;			/* 回退环境变量名称 */
	char	   *compiled;		/* 回退编译的默认值 */
	char	   *val;			/* 选项的当前值，或 NULL */
	char	   *label;			/* 连接对话框中字段的标签 */
	char	   *dispchar;		/* 指示如何在连接对话框中显示该字段。
 * 值为："" 原样显示输入值 "*" 密码字段 - 隐藏值 "D" 调试选项 - 默认不显示 */
	int			dispsize;		/* 对话框中文本的字符大小 */
} PQconninfoOption;

/* ----------------
 * PQArgBlock -- PQfn() 参数的结构
 * ----------------
 */
typedef struct
{
	int			len;
	int			isint;
	union
	{
		int		   *ptr;		/* 不能使用 void（dec 编译器报错） */
		int			integer;
	}			u;
} PQArgBlock;

/* ----------------
 * PGresAttDesc -- 查询结果单个属性（列）的数据
 * ----------------
 */
typedef struct pgresAttDesc
{
	char	   *name;			/* 列名 */
	Oid			tableid;		/* 源表，如果已知 */
	int			columnid;		/* 源列，如果已知 */
	int			format;			/* 值的格式代码（文本/二进制） */
	Oid			typid;			/* 类型ID */
	int			typlen;			/* 类型大小 */
	int			atttypmod;		/* 类型特定的修饰符信息 */
} PGresAttDesc;

/* ----------------
 * libpq的导出函数
 * ----------------
 */

/* === 在 fe-connect.c 中 === */

/* 创建与后端的新客户端连接 */
/* 异步（非阻塞） */
extern PGconn *PQconnectStart(const char *conninfo);
extern PGconn *PQconnectStartParams(const char *const *keywords,
									const char *const *values, int expand_dbname);
extern PostgresPollingStatusType PQconnectPoll(PGconn *conn);

/* 同步（阻塞） */
extern PGconn *PQconnectdb(const char *conninfo);
extern PGconn *PQconnectdbParams(const char *const *keywords,
								 const char *const *values, int expand_dbname);
extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport,
							const char *pgoptions, const char *pgtty,
							const char *dbName,
							const char *login, const char *pwd);

#define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME)  \
	PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL)

/* 关闭当前连接并释放 PGconn 数据结构 */
extern void PQfinish(PGconn *conn);

/* 获取关于 PQconnectdb 知道的连接选项的信息 */
extern PQconninfoOption *PQconndefaults(void);

/* 以与 PQconnectdb 相同的方式解析连接选项 */
extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg);

/* 返回活动连接使用的连接选项 */
extern PQconninfoOption *PQconninfo(PGconn *conn);

/* 释放 PQconndefaults() 或 PQconninfoParse() 返回的数据结构 */
extern void PQconninfoFree(PQconninfoOption *connOptions);

/*
 * 关闭当前连接并用相同的参数重新建立新连接
 */
/* 异步（非阻塞） */
extern int	PQresetStart(PGconn *conn);
extern PostgresPollingStatusType PQresetPoll(PGconn *conn);

/* 同步（阻塞） */
extern void PQreset(PGconn *conn);

/* 请求一个取消结构 */
extern PGcancel *PQgetCancel(PGconn *conn);

/* 释放一个取消结构 */
extern void PQfreeCancel(PGcancel *cancel);

/* 发出取消请求 */
extern int	PQcancel(PGcancel *cancel, char *errbuf, int errbufsize);

/* PQcancel 的向后兼容版本；不是线程安全的 */
extern int	PQrequestCancel(PGconn *conn);

/* PGconn 对象的访问器函数 */
extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
extern char *PQhostaddr(const PGconn *conn);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(const PGconn *conn);
extern PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
extern const char *PQparameterStatus(const PGconn *conn,
									 const char *paramName);
extern int	PQprotocolVersion(const PGconn *conn);
extern int	PQserverVersion(const PGconn *conn);
extern char *PQerrorMessage(const PGconn *conn);
extern int	PQsocket(const PGconn *conn);
extern int	PQbackendPID(const PGconn *conn);
extern PGpipelineStatus PQpipelineStatus(const PGconn *conn);
extern int	PQconnectionNeedsPassword(const PGconn *conn);
extern int	PQconnectionUsedPassword(const PGconn *conn);
extern int	PQclientEncoding(const PGconn *conn);
extern int	PQsetClientEncoding(PGconn *conn, const char *encoding);

/* SSL 信息函数 */
extern int	PQsslInUse(PGconn *conn);
extern void *PQsslStruct(PGconn *conn, const char *struct_name);
extern const char *PQsslAttribute(PGconn *conn, const char *attribute_name);
extern const char *const *PQsslAttributeNames(PGconn *conn);

/* 获取与连接关联的 OpenSSL 结构。如果连接是未加密的或使用其他任何 TLS 库，则返回 NULL。 */
extern void *PQgetssl(PGconn *conn);

/* 告诉 libpq 是否需要初始化 OpenSSL */
extern void PQinitSSL(int do_init);

/* 更详细的方式告诉 libpq 是否需要初始化 OpenSSL */
extern void PQinitOpenSSL(int do_ssl, int do_crypto);

/* 如果使用 GSSAPI 加密，则返回 true */
extern int	PQgssEncInUse(PGconn *conn);

/* 如果使用 GSSAPI，则返回 GSSAPI 上下文 */
extern void *PQgetgssctx(PGconn *conn);

/* 设置 PQerrorMessage 和 PQresultErrorMessage 的详细程度 */
extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);

/* 设置 PQerrorMessage 和 PQresultErrorMessage 的 CONTEXT 可见性 */
extern PGContextVisibility PQsetErrorContextVisibility(PGconn *conn,
													   PGContextVisibility show_context);

/* 覆盖默认的通知处理例程 */
extern PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn,
											PQnoticeReceiver proc,
											void *arg);
extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
											  PQnoticeProcessor proc,
											  void *arg);

/*
 *	   用于设置回调，以防止对
 *	   libpq 需要的非线程安全函数进行并发访问。
 *	   默认实现使用 libpq 内部互斥锁。
 *	   仅在多线程应用程序中需要，该应用程序在自身和 PostgreSQL 连接中均使用 kerberos。
 */
typedef void (*pgthreadlock_t) (int acquire);

extern pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler);

/* === 在 fe-trace.c 中 === */
extern void PQtrace(PGconn *conn, FILE *debug_port);
extern void PQuntrace(PGconn *conn);

/* 控制跟踪输出的标志： */
/* 从每行省略时间戳 */
#define PQTRACE_SUPPRESS_TIMESTAMPS		(1<<0)
/* 隐藏某些消息的部分内容，用于测试框架 */
#define PQTRACE_REGRESS_MODE			(1<<1)
extern void PQsetTraceFlags(PGconn *conn, int flags);

/* === 在 fe-exec.c 中 === */

/* 简单的同步查询 */
extern PGresult *PQexec(PGconn *conn, const char *query);
extern PGresult *PQexecParams(PGconn *conn,
							  const char *command,
							  int nParams,
							  const Oid *paramTypes,
							  const char *const *paramValues,
							  const int *paramLengths,
							  const int *paramFormats,
							  int resultFormat);
extern PGresult *PQprepare(PGconn *conn, const char *stmtName,
						   const char *query, int nParams,
						   const Oid *paramTypes);
extern PGresult *PQexecPrepared(PGconn *conn,
								const char *stmtName,
								int nParams,
								const char *const *paramValues,
								const int *paramLengths,
								const int *paramFormats,
								int resultFormat);

/* 多结果或异步查询的接口 */
#define PQ_QUERY_PARAM_MAX_LIMIT 65535

extern int	PQsendQuery(PGconn *conn, const char *query);
extern int	PQsendQueryParams(PGconn *conn,
							  const char *command,
							  int nParams,
							  const Oid *paramTypes,
							  const char *const *paramValues,
							  const int *paramLengths,
							  const int *paramFormats,
							  int resultFormat);
extern int	PQsendPrepare(PGconn *conn, const char *stmtName,
						  const char *query, int nParams,
						  const Oid *paramTypes);
extern int	PQsendQueryPrepared(PGconn *conn,
								const char *stmtName,
								int nParams,
								const char *const *paramValues,
								const int *paramLengths,
								const int *paramFormats,
								int resultFormat);
extern int	PQsetSingleRowMode(PGconn *conn);
extern PGresult *PQgetResult(PGconn *conn);

/* 管理异步查询的例程 */
extern int	PQisBusy(PGconn *conn);
extern int	PQconsumeInput(PGconn *conn);

/* 管道模式管理的例程 */
extern int	PQenterPipelineMode(PGconn *conn);
extern int	PQexitPipelineMode(PGconn *conn);
extern int	PQpipelineSync(PGconn *conn);
extern int	PQsendFlushRequest(PGconn *conn);

/* LISTEN/NOTIFY 支持 */
extern PGnotify *PQnotifies(PGconn *conn);

/* 复制进/出的例程 */
extern int	PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
extern int	PQputCopyEnd(PGconn *conn, const char *errormsg);
extern int	PQgetCopyData(PGconn *conn, char **buffer, int async);

/* 复制进/出的弃用例程 */
extern int	PQgetline(PGconn *conn, char *string, int length);
extern int	PQputline(PGconn *conn, const char *string);
extern int	PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
extern int	PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
extern int	PQendcopy(PGconn *conn);

/* 设置与后端的阻塞/非阻塞连接 */
extern int	PQsetnonblocking(PGconn *conn, int arg);
extern int	PQisnonblocking(const PGconn *conn);
extern int	PQisthreadsafe(void);
extern PGPing PQping(const char *conninfo);
extern PGPing PQpingParams(const char *const *keywords,
						   const char *const *values, int expand_dbname);

/* 强制将写缓冲区写入（或至少尝试） */
extern int	PQflush(PGconn *conn);

/*
 * "快速路径"接口 --- 实际上不推荐应用程序使用
 */
extern PGresult *PQfn(PGconn *conn,
					  int fnid,
					  int *result_buf,
					  int *result_len,
					  int result_is_int,
					  const PQArgBlock *args,
					  int nargs);

/* PGresult对象的访问器函数 */
extern ExecStatusType PQresultStatus(const PGresult *res);
extern char *PQresStatus(ExecStatusType status);
extern char *PQresultErrorMessage(const PGresult *res);
extern char *PQresultVerboseErrorMessage(const PGresult *res,
										 PGVerbosity verbosity,
										 PGContextVisibility show_context);
extern char *PQresultErrorField(const PGresult *res, int fieldcode);
extern int	PQntuples(const PGresult *res);
extern int	PQnfields(const PGresult *res);
extern int	PQbinaryTuples(const PGresult *res);
extern char *PQfname(const PGresult *res, int field_num);
extern int	PQfnumber(const PGresult *res, const char *field_name);
extern Oid	PQftable(const PGresult *res, int field_num);
extern int	PQftablecol(const PGresult *res, int field_num);
extern int	PQfformat(const PGresult *res, int field_num);
extern Oid	PQftype(const PGresult *res, int field_num);
extern int	PQfsize(const PGresult *res, int field_num);
extern int	PQfmod(const PGresult *res, int field_num);
extern char *PQcmdStatus(PGresult *res);
extern char *PQoidStatus(const PGresult *res);	/* 旧的和丑陋的 */
extern Oid	PQoidValue(const PGresult *res);	/* 新的和改进的 */
extern char *PQcmdTuples(PGresult *res);
extern char *PQgetvalue(const PGresult *res, int tup_num, int field_num);
extern int	PQgetlength(const PGresult *res, int tup_num, int field_num);
extern int	PQgetisnull(const PGresult *res, int tup_num, int field_num);
extern int	PQnparams(const PGresult *res);
extern Oid	PQparamtype(const PGresult *res, int param_num);

/* 描述预编译语句和门户 */
extern PGresult *PQdescribePrepared(PGconn *conn, const char *stmt);
extern PGresult *PQdescribePortal(PGconn *conn, const char *portal);
extern int	PQsendDescribePrepared(PGconn *conn, const char *stmt);
extern int	PQsendDescribePortal(PGconn *conn, const char *portal);

/* 删除一个PGresult */
extern void PQclear(PGresult *res);

/* 用于释放其他已分配的结果，例如PGnotify结构 */
extern void PQfreemem(void *ptr);

/* 存在是为了向后兼容。 bjm 2003-03-24 */
#define PQfreeNotify(ptr) PQfreemem(ptr)

/* 当没有提供密码时的错误。 */
/* 注意：依赖此项已被弃用；使用PQconnectionNeedsPassword()。 */
#define PQnoPasswordSupplied	"fe_sendauth: no password supplied\n"

/* 创建和操纵PGresults */
extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
extern PGresult *PQcopyResult(const PGresult *src, int flags);
extern int	PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs);
extern void *PQresultAlloc(PGresult *res, size_t nBytes);
extern size_t PQresultMemorySize(const PGresult *res);
extern int	PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len);

/* 在查询中包含字符串之前进行转义。 */
extern size_t PQescapeStringConn(PGconn *conn,
								 char *to, const char *from, size_t length,
								 int *error);
extern char *PQescapeLiteral(PGconn *conn, const char *str, size_t len);
extern char *PQescapeIdentifier(PGconn *conn, const char *str, size_t len);
extern unsigned char *PQescapeByteaConn(PGconn *conn,
										const unsigned char *from, size_t from_length,
										size_t *to_length);
extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
									  size_t *retbuflen);

/* 这些形式已被弃用！ */
extern size_t PQescapeString(char *to, const char *from, size_t length);
extern unsigned char *PQescapeBytea(const unsigned char *from, size_t from_length,
									size_t *to_length);



/* === 在 fe-print.c 中 === */

extern void PQprint(FILE *fout, /* 输出流 */
					const PGresult *res,
					const PQprintOpt *ps);	/* 选项结构 */

/*
 * 真正古老的打印例程
 */
extern void PQdisplayTuples(const PGresult *res,
							FILE *fp,	/* 输出发送的位置 */
							int fillAlign,	/* 用空格填充字段 */
							const char *fieldSep,	/* 字段分隔符 */
							int printHeader,	/* 显示标题？ */
							int quiet);

extern void PQprintTuples(const PGresult *res,
						  FILE *fout,	/* 输出流 */
						  int PrintAttNames,	/* 打印属性名称 */
						  int TerseOutput,	/* 分隔栏 */
						  int colWidth);	/* 列的宽度，如果为0，则使用
											 * 变量宽度 */


/* === 在 fe-lobj.c 中 === */

/* 大对象访问例程 */
extern int	lo_open(PGconn *conn, Oid lobjId, int mode);
extern int	lo_close(PGconn *conn, int fd);
extern int	lo_read(PGconn *conn, int fd, char *buf, size_t len);
extern int	lo_write(PGconn *conn, int fd, const char *buf, size_t len);
extern int	lo_lseek(PGconn *conn, int fd, int offset, int whence);
extern pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence);
extern Oid	lo_creat(PGconn *conn, int mode);
extern Oid	lo_create(PGconn *conn, Oid lobjId);
extern int	lo_tell(PGconn *conn, int fd);
extern pg_int64 lo_tell64(PGconn *conn, int fd);
extern int	lo_truncate(PGconn *conn, int fd, size_t len);
extern int	lo_truncate64(PGconn *conn, int fd, pg_int64 len);
extern int	lo_unlink(PGconn *conn, Oid lobjId);
extern Oid	lo_import(PGconn *conn, const char *filename);
extern Oid	lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId);
extern int	lo_export(PGconn *conn, Oid lobjId, const char *filename);

/* === 在 fe-misc.c 中 === */

/* 获取使用中的libpq库版本 */
extern int	PQlibVersion(void);

/* 确定*s处多字节编码字符的长度 */
extern int	PQmblen(const char *s, int encoding);

/* 同上，但不得超过字符串s末尾的距离 */
extern int	PQmblenBounded(const char *s, int encoding);

/* 确定*s处多字节编码字符的显示长度 */
extern int	PQdsplen(const char *s, int encoding);

/* 从环境变量PGCLIENTENCODING获取编码ID */
extern int	PQenv2encoding(void);

/* === 在 fe-auth.c 中 === */

extern char *PQencryptPassword(const char *passwd, const char *user);
extern char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm);

/* === 在 encnames.c 中 === */

extern int	pg_char_to_encoding(const char *name);
extern const char *pg_encoding_to_char(int encoding);
extern int	pg_valid_server_encoding_id(int encoding);

/* === 在 fe-secure-openssl.c 中 === */

/* 支持通过回调覆盖sslpassword处理 */
typedef int (*PQsslKeyPassHook_OpenSSL_type) (char *buf, int size, PGconn *conn);
extern PQsslKeyPassHook_OpenSSL_type PQgetSSLKeyPassHook_OpenSSL(void);
extern void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
extern int	PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn);

#ifdef __cplusplus
}
#endif

#endif							/* LIBPQ_FE_H */
